/*******************************************************************************
 * Copyright IBM Corp. and others 2000
 *
 * This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License 2.0 which accompanies this
 * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
 * or the Apache License, Version 2.0 which accompanies this distribution
 * and is available at https://www.apache.org/licenses/LICENSE-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License, v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception [1] and GNU General Public
 * License, version 2 with the OpenJDK Assembly Exception [2].
 *
 * [1] https://www.gnu.org/software/classpath/license.html
 * [2] https://openjdk.org/legal/assembly-exception.html
 *
 * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
 *******************************************************************************/

#include "p/codegen/PPCInstruction.hpp"

#include <stddef.h>
#include <stdint.h>
#include "codegen/CodeGenerator.hpp"
#include "codegen/InstOpCode.hpp"
#include "codegen/Instruction.hpp"
#include "codegen/Machine.hpp"
#include "codegen/MemoryReference.hpp"
#include "codegen/RealRegister.hpp"
#include "codegen/Register.hpp"
#include "codegen/RegisterConstants.hpp"
#include "codegen/RegisterDependency.hpp"
#include "codegen/RegisterDependencyStruct.hpp"
#include "compile/Compilation.hpp"
#include "control/Options.hpp"
#include "control/Options_inlines.hpp"
#include "env/CompilerEnv.hpp"
#include "env/Processors.hpp"
#include "env/TRMemory.hpp"
#include "il/DataTypes.hpp"
#include "il/ILOps.hpp"
#include "il/LabelSymbol.hpp"
#include "il/Node.hpp"
#include "infra/Assert.hpp"
#include "p/codegen/GenerateInstructions.hpp"
#include "p/codegen/PPCOpsDefines.hpp"
#include "p/codegen/PPCOutOfLineCodeSection.hpp"

namespace TR { class SymbolReference; }


// TR::LabelInstruction function
void TR::PPCLabelInstruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   TR::Compilation *comp = cg()->comp();
   if( TR::Instruction::getDependencyConditions() )
      {
      TR::Instruction::getDependencyConditions()->assignPostConditionRegisters(this, kindToBeAssigned, cg());
      TR::Instruction::getDependencyConditions()->assignPreConditionRegisters(this->getPrev(), kindToBeAssigned, cg());
      }

   TR::Machine *machine = cg()->machine();
   if (isLabel() && getLabelSymbol()->isEndOfColdInstructionStream())
      {
      // A label instruction coming back from OOL.
      //
      // This label is the end of the hot instruction stream (i.e., the fallthru path).
      //
      if (comp->getOption(TR_TraceRA))
         traceMsg (comp,"\nOOL: 1. Taking register state snap shot\n");
      cg()->setIsOutOfLineHotPath(true);
      machine->takeRegisterStateSnapShot();

      // Prevent spilled registers from reclaiming their backing store if they
      // become unspilled.  This will ensure a spilled register will receive the
      // same backing store if it is spilled on either path of the control flow.
      //
      cg()->lockFreeSpillList();
      }

   if (isBranchOp() && !usesCountRegister() && getLabelSymbol()->isEndOfColdInstructionStream())
      {
      // This is the branch at the end of the cold instruction stream to the end of
      // the hot instruction stream (or fallthru path).
      //
      // Start RA for OOL cold path, restore register state from snap shot
      //
      if (comp->getOption(TR_TraceRA))
         traceMsg (comp, "\nOOL: 1. Restoring Register state from snap shot\n");
      cg()->setIsOutOfLineHotPath(false);
      machine->restoreRegisterStateFromSnapShot();
      }

   if (((isBranchOp() && !usesCountRegister()) || isVirtualGuardNOPInstruction()) && getLabelSymbol()->isStartOfColdInstructionStream())
      {
      // This may be an unconditional branch to the OOL code.  This can occur when the
      // array is provably discontiguous but the BNDCHKwithSpineCHK node couldn't
      // be folded away.
      //

      // Switch to the outlined instruction stream and assign registers.
      //
      TR_PPCOutOfLineCodeSection *oi = cg()->findOutLinedInstructionsFromLabel(getLabelSymbol());
      TR_ASSERT(oi, "Could not find PPCOutOfLineCodeSection stream from label.  instr=%p, label=%p\n", this, getLabelSymbol());

      if (!oi->hasBeenRegisterAssigned())
         oi->assignRegisters(kindToBeAssigned);

      if (cg()->getDebug())
         cg()->traceRegisterAssignment("OOL: Finished register assignment in OOL section\n");

      // Unlock the free spill list.
      //
      cg()->unlockFreeSpillList();

      // Disassociate backing storage that was previously reserved for a spilled virtual if
      // virtual is no longer spilled. This occurs because the the free spill list was
      // locked.
      //
      machine->disassociateUnspilledBackingStorage();
      }
   }

// TR::PPCDepInstruction:: member functions

void TR::PPCDepInstruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   if( getOpCodeValue() != TR::InstOpCode::assocreg )
      {
      getDependencyConditions()->assignPostConditionRegisters(this, kindToBeAssigned, cg());
      getDependencyConditions()->assignPreConditionRegisters(this->getPrev(), kindToBeAssigned, cg());
      }
   else
      {
      // Restore the register association using the assocreg instruction info
      int i;
      TR::RegisterDependencyConditions *assocreg = getDependencyConditions();
      TR::RegisterDependency *assoc;
      for( i=0 ; i < assocreg->getNumPostConditions() ; i++ )
         {
         assoc = assocreg->getPostConditions()->getRegisterDependency(i);
         assoc->getRegister()->setAssociation( assoc->getRealRegister() );
         }
      }
   }

bool TR::PPCDepInstruction::refsRegister(TR::Register *reg)
   {
   return _conditions->refsRegister(reg);
   }

bool TR::PPCDepInstruction::defsRegister(TR::Register *reg)
   {
   return _conditions->defsRegister(reg);
   }

bool TR::PPCDepInstruction::defsRealRegister(TR::Register *reg)
   {
   return _conditions->defsRealRegister(reg);
   }

bool TR::PPCDepInstruction::usesRegister(TR::Register *reg)
   {
   return _conditions->usesRegister(reg);
   }

// TR::PPCDepLabelInstruction:: member functions

void TR::PPCDepLabelInstruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   getDependencyConditions()->assignPostConditionRegisters(this, kindToBeAssigned, cg());

   TR::PPCLabelInstruction::assignRegisters(kindToBeAssigned);

   getDependencyConditions()->assignPreConditionRegisters(this->getPrev(), kindToBeAssigned, cg());
   }

bool TR::PPCDepLabelInstruction::refsRegister(TR::Register *reg)
   {
   return _conditions->refsRegister(reg);
   }

bool TR::PPCDepLabelInstruction::defsRegister(TR::Register *reg)
   {
   return _conditions->defsRegister(reg);
   }

bool TR::PPCDepLabelInstruction::defsRealRegister(TR::Register *reg)
   {
   return _conditions->defsRealRegister(reg);
   }

bool TR::PPCDepLabelInstruction::usesRegister(TR::Register *reg)
   {
   return _conditions->usesRegister(reg);
   }

// TR::PPCConditionalBranchInstruction: member functions

TR::PPCConditionalBranchInstruction *
TR::PPCConditionalBranchInstruction::getPPCConditionalBranchInstruction()
   {
   return this;
   }

void TR::PPCConditionalBranchInstruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   TR::Register           *virtualRegister = getConditionRegister();
   TR::RealRegister       *assignedRegister = virtualRegister->getAssignedRealRegister();
   TR::Machine *machine = cg()->machine();

   if (assignedRegister == NULL)
      {
      assignedRegister = machine->assignOneRegister(this, virtualRegister, false);
      }

   machine->decFutureUseCountAndUnlatch(virtualRegister);

   setConditionRegister(assignedRegister);

   if (getLabelSymbol()->isStartOfColdInstructionStream())
      {
      // Switch to the outlined instruction stream and assign registers.
      //
      TR_PPCOutOfLineCodeSection *oi = cg()->findOutLinedInstructionsFromLabel(getLabelSymbol());
      TR_ASSERT(oi, "Could not find PPCOutOfLineCodeSection stream from label.  instr=%p, label=%p\n", this, getLabelSymbol());
      if (!oi->hasBeenRegisterAssigned())
         oi->assignRegisters(kindToBeAssigned);
      if (cg()->getDebug())
            cg()->traceRegisterAssignment("OOL: Finished register assignment in OOL section\n");

      // Unlock the free spill list.
      //
      cg()->unlockFreeSpillList();

      // Disassociate backing storage that was previously reserved for a spilled virtual if
      // virtual is no longer spilled. This occurs because the the free spill list was
      // locked.
      //
      machine->disassociateUnspilledBackingStorage();
      }
   }

bool TR::PPCConditionalBranchInstruction::refsRegister(TR::Register *reg)
   {
   if (getConditionRegister() == reg)
      return(true);
   return(false);
   }

bool TR::PPCConditionalBranchInstruction::defsRegister(TR::Register *reg)
   {
   return(false);
   }

bool TR::PPCConditionalBranchInstruction::defsRealRegister(TR::Register *reg)
   {
   return(false);
   }

bool TR::PPCConditionalBranchInstruction::usesRegister(TR::Register *reg)
   {
   if (getConditionRegister() == reg)
      return(true);
   return(false);
   }

// TR::PPCDepConditionalBranchInstruction: member functions

void TR::PPCDepConditionalBranchInstruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   TR::Register     *virtualRegister = getConditionRegister();

   virtualRegister->block();

   getDependencyConditions()->assignPostConditionRegisters(this, kindToBeAssigned, cg());

   virtualRegister->unblock();

   TR::PPCConditionalBranchInstruction::assignRegisters(kindToBeAssigned);

   virtualRegister->block();

   getDependencyConditions()->assignPreConditionRegisters(this->getPrev(), kindToBeAssigned, cg());

   virtualRegister->unblock();
   }

bool TR::PPCDepConditionalBranchInstruction::refsRegister(TR::Register *reg)
   {
   if (getConditionRegister()==reg || _conditions->refsRegister(reg))
      return(true);
   return(false);
   }

bool TR::PPCDepConditionalBranchInstruction::defsRegister(TR::Register *reg)
   {
   return _conditions->defsRegister(reg);
   }

bool TR::PPCDepConditionalBranchInstruction::defsRealRegister(TR::Register *reg)
   {
   return _conditions->defsRealRegister(reg);
   }

bool TR::PPCDepConditionalBranchInstruction::usesRegister(TR::Register *reg)
   {
   if (getConditionRegister()==reg || _conditions->usesRegister(reg))
      return(true);
   return(false);
   }

// TR::PPCImmInstruction:: member functions


// The following safe virtual downcast method is only used in an assertion
// check within "toPPCImmInstruction"
#if defined(DEBUG) || defined(PROD_WITH_ASSUMES)
TR::PPCImmInstruction *TR::PPCImmInstruction::getPPCImmInstruction()
   {
   return this;
   }
#endif

// TR::PPCSrc1Instruction:: member functions

bool TR::PPCSrc1Instruction::refsRegister(TR::Register *reg)
   {
   if (reg == getSource1Register())
      {
      return true;
      }
   return false;
   }

void TR::PPCSrc1Instruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   TR::Register           *virtualRegister = getSource1Register();
   TR::RealRegister       *assignedRegister = virtualRegister->getAssignedRealRegister();
   TR::Machine *machine = cg()->machine();

   if (assignedRegister == NULL)
      {
      assignedRegister = machine->assignOneRegister(this, virtualRegister, false);
      }

   machine->decFutureUseCountAndUnlatch(virtualRegister);

   setSource1Register(assignedRegister);
   }


bool TR::PPCSrc1Instruction::defsRegister(TR::Register *reg)
   {
   return false;
   }

bool TR::PPCSrc1Instruction::defsRealRegister(TR::Register *reg)
   {
   return false;
   }

bool TR::PPCSrc1Instruction::usesRegister(TR::Register *reg)
   {
   if (reg == getSource1Register())
      {
      return true;
      }
   return false;
   }

// TR::PPCTrg1Instruction:: member functions

bool TR::PPCTrg1Instruction::refsRegister(TR::Register *reg)
   {
   if (reg == getTargetRegister() || TR::Instruction::refsRegister(reg) )
      {
      return true;
      }
   return false;
   }

bool TR::PPCTrg1Instruction::defsRegister(TR::Register *reg)
   {
   if (reg == getTargetRegister() || TR::Instruction::defsRegister(reg) )
      {
      return true;
      }
   return false;
   }

bool TR::PPCTrg1Instruction::defsRealRegister(TR::Register *reg)
   {
   if (reg == getTargetRegister()->getAssignedRegister() || TR::Instruction::defsRealRegister(reg) )
      {
      return true;
      }
   return false;
   }

bool TR::PPCTrg1Instruction::usesRegister(TR::Register *reg)
   {
   return TR::Instruction::usesRegister(reg);
   }

void TR::PPCTrg1Instruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   assignRegisters(kindToBeAssigned, false);
   }

void TR::PPCTrg1Instruction::assignRegisters(TR_RegisterKinds kindToBeAssigned, bool excludeGPR0)
   {
   TR::Register           *virtualRegister = getTargetRegister();
   TR::RealRegister       *assignedRegister = virtualRegister->getAssignedRealRegister();
   TR::Machine *machine = cg()->machine();
   TR_RegisterKinds       kindOfRegister = virtualRegister->getKind();

   TR::Instruction::assignRegisters( kindToBeAssigned );

   if (excludeGPR0 && (assignedRegister != NULL) &&
       (toRealRegister(assignedRegister) == machine->getRealRegister(TR::RealRegister::gr0)))
      {
      TR::RealRegister    *alternativeRegister;

      if ((alternativeRegister = machine->findBestFreeRegister(this, kindOfRegister, excludeGPR0, false, virtualRegister)) == NULL)
         {
         cg()->setRegisterAssignmentFlag(TR_RegisterSpilled);
         alternativeRegister = machine->freeBestRegister(this, virtualRegister, NULL, excludeGPR0);
         }
      machine->coerceRegisterAssignment(this, virtualRegister, toRealRegister(alternativeRegister)->getRegisterNumber());
      assignedRegister = alternativeRegister;
      }
   else
      {
      if (assignedRegister == NULL)
         {
         assignedRegister = machine->assignOneRegister(this, virtualRegister, excludeGPR0);
         }
      }

   machine->decFutureUseCountAndUnlatch(virtualRegister);

   setTargetRegister(assignedRegister);
   }

// TR::PPCTrg1Src1Instruction:: member functions

TR::PPCTrg1Src1Instruction::PPCTrg1Src1Instruction(
      TR::InstOpCode::Mnemonic op,
      TR::Node *n,
      TR::Register *treg,
      TR::Register *sreg,
      TR::CodeGenerator *cg)
   : TR::PPCTrg1Instruction(op, n, treg, cg),
      _source1Register(sreg)
   {
   useRegister(sreg);
   if (TR::InstOpCode(op).excludesR0ForRA())
      {
      cg->addRealRegisterInterference(sreg, TR::RealRegister::gr0);
      }
   }

TR::PPCTrg1Src1Instruction::PPCTrg1Src1Instruction(
      TR::InstOpCode::Mnemonic op,
      TR::Node *n,
      TR::Register *treg,
      TR::Register *sreg,
      TR::Instruction *precedingInstruction,
      TR::CodeGenerator *cg)
   : TR::PPCTrg1Instruction(op, n, treg, precedingInstruction, cg),
      _source1Register(sreg)
   {
   useRegister(sreg);
   if (TR::InstOpCode(op).excludesR0ForRA())
      {
      cg->addRealRegisterInterference(sreg, TR::RealRegister::gr0);
      }
   }

bool TR::PPCTrg1Src1Instruction::refsRegister(TR::Register *reg)
   {
   if (reg == getSource1Register() || TR::PPCTrg1Instruction::refsRegister(reg))
      {
      return true;
      }
   return false;
   }

bool TR::PPCTrg1Src1Instruction::defsRegister(TR::Register *reg)
   {
   return TR::PPCTrg1Instruction::defsRegister(reg);
   }

bool TR::PPCTrg1Src1Instruction::defsRealRegister(TR::Register *reg)
   {
   return TR::PPCTrg1Instruction::defsRealRegister(reg);
   }

bool TR::PPCTrg1Src1Instruction::usesRegister(TR::Register *reg)
   {
   if (reg == getSource1Register() || TR::PPCTrg1Instruction::usesRegister(reg) )
      {
      return true;
      }
   return false;
   }

void TR::PPCTrg1Src1Instruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   TR::Register      *sourceVirtual = getSource1Register();
   TR::Register      *targetVirtual = getTargetRegister();
   TR::Machine *machine = cg()->machine();
   TR::RealRegister  *assignedRegister;
   TR_RegisterKinds  kindOfRegister = sourceVirtual->getKind();
   bool              excludeGPR0 = getOpCode().excludesR0ForRA();

   sourceVirtual->block();

   if ((sourceVirtual == targetVirtual) && excludeGPR0)
      TR::PPCTrg1Instruction::assignRegisters(kindToBeAssigned, true);
   else
      TR::PPCTrg1Instruction::assignRegisters(kindToBeAssigned, false);

   sourceVirtual->unblock();

   targetVirtual->block();
   assignedRegister = sourceVirtual->getAssignedRealRegister();
   if (excludeGPR0 && (assignedRegister != NULL) &&
       (toRealRegister(assignedRegister) == machine->getRealRegister(TR::RealRegister::gr0)))
      {
      TR::RealRegister    *alternativeRegister;

      if ((alternativeRegister = machine->findBestFreeRegister(this, kindOfRegister, excludeGPR0, false, sourceVirtual)) == NULL)
         {
         cg()->setRegisterAssignmentFlag(TR_RegisterSpilled);
         alternativeRegister = machine->freeBestRegister(this, sourceVirtual, NULL, excludeGPR0);
         }
      machine->coerceRegisterAssignment(this, sourceVirtual, toRealRegister(alternativeRegister)->getRegisterNumber());
      assignedRegister = alternativeRegister;
      }
   else
      {
      if (assignedRegister == NULL)
         {
         assignedRegister = machine->assignOneRegister(this, sourceVirtual, excludeGPR0);
         }
      }
   targetVirtual->unblock();

   machine->decFutureUseCountAndUnlatch(sourceVirtual);

   setSource1Register(assignedRegister);
   }

// TR::PPCTrg1Src1ImmInstruction:: member functions

// TR::PPCSrc2Instruction:: member functions

TR::PPCSrc2Instruction::PPCSrc2Instruction(
      TR::InstOpCode::Mnemonic op,
      TR::Node *n,
      TR::Register *s1reg,
      TR::Register *s2reg,
      TR::CodeGenerator *cg)
   : TR::Instruction(op, n, cg), _source1Register(s1reg), _source2Register(s2reg)
   {
   useRegister(s1reg);
   useRegister(s2reg);
   if (TR::InstOpCode(op).excludesR0ForRA())
      cg->addRealRegisterInterference(s2reg, TR::RealRegister::gr0);
   }

TR::PPCSrc2Instruction::PPCSrc2Instruction(
      TR::InstOpCode::Mnemonic op,
      TR::Node *n,
      TR::Register *s1reg,
      TR::Register *s2reg,
      TR::Instruction *precedingInstruction,
      TR::CodeGenerator *cg)
   : TR::Instruction(op, n, precedingInstruction, cg), _source1Register(s1reg), _source2Register(s2reg)
   {
   useRegister(s1reg);
   useRegister(s2reg);
   if (TR::InstOpCode(op).excludesR0ForRA())
      cg->addRealRegisterInterference(s2reg, TR::RealRegister::gr0);
   }

bool TR::PPCSrc2Instruction::refsRegister(TR::Register *reg)
   {
   if (reg == getSource1Register() || reg == getSource2Register())
      {
      return true;
      }
   return false;
   }

bool TR::PPCSrc2Instruction::defsRegister(TR::Register *reg)
   {
   return false;
   }

bool TR::PPCSrc2Instruction::defsRealRegister(TR::Register *reg)
   {
   return false;
   }

bool TR::PPCSrc2Instruction::usesRegister(TR::Register *reg)
   {
   if ( reg == getSource1Register()  ||
        reg == getSource2Register())
      {
      return true;
      }
   return false;
   }

void TR::PPCSrc2Instruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   TR::Register           *virtualRegister1 = getSource1Register();
   TR::Register           *virtualRegister2 = getSource2Register();
   TR::RealRegister       *assignedRegister;
   TR::Machine *machine = cg()->machine();
   bool excludeGPR0 = getOpCode().excludesR0ForRA();

   virtualRegister1->block();

   assignedRegister = virtualRegister2->getAssignedRealRegister();
   if (excludeGPR0 && (assignedRegister != NULL) &&
       (toRealRegister(assignedRegister) == machine->getRealRegister(TR::RealRegister::gr0)))
      {
      TR::RealRegister    *alternativeRegister;

      if ((alternativeRegister = machine->findBestFreeRegister(this, virtualRegister2->getKind(), excludeGPR0, false, virtualRegister2)) == NULL)
         {
         cg()->setRegisterAssignmentFlag(TR_RegisterSpilled);
         alternativeRegister = machine->freeBestRegister(this, virtualRegister2, NULL, excludeGPR0);
         }
      machine->coerceRegisterAssignment(this, virtualRegister2, toRealRegister(alternativeRegister)->getRegisterNumber());
      assignedRegister = alternativeRegister;
      }
   else if (assignedRegister == NULL)
      {
      assignedRegister = machine->assignOneRegister(this, virtualRegister2, excludeGPR0);
      }
   setSource2Register(assignedRegister);

   virtualRegister1->unblock();
   virtualRegister2->block();

   assignedRegister = virtualRegister1->getAssignedRealRegister();
   if (assignedRegister == NULL)
      {
      assignedRegister = machine->assignOneRegister(this, virtualRegister1, false);
      }
   setSource1Register(assignedRegister);

   virtualRegister2->unblock();

   machine->decFutureUseCountAndUnlatch(virtualRegister1);
   machine->decFutureUseCountAndUnlatch(virtualRegister2);
   }

// TR::PPCSrc3Instruction:: member functions

void TR::PPCSrc3Instruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   TR::Register *source3Virtual = getSource3Register();
   TR::Machine *machine = cg()->machine();
   TR::RealRegister *assignedRegister;

   source3Virtual->block();
   TR::PPCSrc2Instruction::assignRegisters(kindToBeAssigned);
   source3Virtual->unblock();

   getSource1Register()->block();
   getSource2Register()->block();

   assignedRegister = source3Virtual->getAssignedRealRegister();
   if (assignedRegister == NULL)
      {
      assignedRegister = machine->assignOneRegister(this, source3Virtual, false);
      }

   getSource2Register()->unblock();
   getSource1Register()->unblock();

   machine->decFutureUseCountAndUnlatch(source3Virtual);
   setSource3Register(assignedRegister);
   }

// TR::PPCTrg1Src2Instruction:: member functions

bool TR::PPCTrg1Src2Instruction::refsRegister(TR::Register *reg)
   {
   if (reg == getTargetRegister() || reg == getSource1Register() || reg == getSource2Register())
      {
      return true;
      }
   return false;
   }

bool TR::PPCTrg1Src2Instruction::defsRegister(TR::Register *reg)
   {
   if (reg == getTargetRegister())
      {
      return true;
      }
   return false;
   }

bool TR::PPCTrg1Src2Instruction::defsRealRegister(TR::Register *reg)
   {
   if (reg == getTargetRegister()->getAssignedRegister())
      {
      return true;
      }
   return false;
   }

bool TR::PPCTrg1Src2Instruction::usesRegister(TR::Register *reg)
   {
   if ( reg == getSource1Register()  ||
        reg == getSource2Register())
      {
      return true;
      }
   return false;
   }

void TR::PPCTrg1Src2Instruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   TR::Register        *source2Virtual = getSource2Register();
   TR::Machine *machine = cg()->machine();
   TR::RealRegister    *assignedRegister;

   source2Virtual->block();
   TR::PPCTrg1Src1Instruction::assignRegisters(kindToBeAssigned);
   source2Virtual->unblock();

   getSource1Register()->block();
   getTargetRegister()->block();

   assignedRegister = source2Virtual->getAssignedRealRegister();
   if (assignedRegister == NULL)
      {
      assignedRegister = machine->assignOneRegister(this, source2Virtual, false);
      }

   getTargetRegister()->unblock();
   getSource1Register()->unblock();

   machine->decFutureUseCountAndUnlatch(source2Virtual);

   setSource2Register(assignedRegister);
   }


// TR::PPCTrg1Src3Instruction:: member functions

bool TR::PPCTrg1Src3Instruction::refsRegister(TR::Register *reg)
   {
   if (reg == getTargetRegister() || reg == getSource1Register() || reg == getSource2Register() ||
       reg == getSource3Register())
      {
      return true;
      }
   return false;
   }

bool TR::PPCTrg1Src3Instruction::usesRegister(TR::Register *reg)
   {
   if ( reg == getSource1Register()  ||
        reg == getSource2Register()  ||
        reg == getSource3Register())
      {
      return true;
      }
   return false;
   }

void TR::PPCTrg1Src3Instruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   TR::Register        *source3Virtual = getSource3Register();
   TR::Machine *machine = cg()->machine();
   TR::RealRegister    *assignedRegister;

   source3Virtual->block();
   TR::PPCTrg1Src2Instruction::assignRegisters(kindToBeAssigned);
   source3Virtual->unblock();

   getSource1Register()->block();
   getSource2Register()->block();
   getTargetRegister()->block();

   assignedRegister = source3Virtual->getAssignedRealRegister();
   if (assignedRegister == NULL)
      {
      assignedRegister = machine->assignOneRegister(this, source3Virtual, false);
      }

   getTargetRegister()->unblock();
   getSource2Register()->unblock();
   getSource1Register()->unblock();

   machine->decFutureUseCountAndUnlatch(source3Virtual);

   setSource3Register(assignedRegister);
   }

TR::PPCMemInstruction::PPCMemInstruction(
      TR::InstOpCode::Mnemonic op,
      TR::Node *n,
      TR::MemoryReference *mf,
      TR::CodeGenerator *cg)
   : TR::Instruction(op, n, cg),
      _memoryReference(mf)
   {
   if (getOpCode().offsetRequiresWordAlignment())
      {
      mf->setOffsetRequiresWordAlignment(n, cg, getPrev());
      }

   mf->bookKeepingRegisterUses(this, cg);
   TR::Register *baseReg = mf->getBaseRegister();
   if (baseReg != NULL)
      {
      cg->addRealRegisterInterference(baseReg, TR::RealRegister::gr0);
      }
   }

TR::PPCMemInstruction::PPCMemInstruction(
      TR::InstOpCode::Mnemonic op,
      TR::Node *n,
      TR::MemoryReference *mf,
      TR::Instruction *precedingInstruction,
      TR::CodeGenerator *cg)
   : TR::Instruction(op, n, precedingInstruction, cg),
      _memoryReference(mf)
   {
   if (getOpCode().offsetRequiresWordAlignment())
      {
      mf->setOffsetRequiresWordAlignment(n, cg, getPrev());
      }
   mf->bookKeepingRegisterUses(this, cg);
   TR::Register *baseReg = mf->getBaseRegister();
   if (baseReg != NULL)
      {
      cg->addRealRegisterInterference(baseReg, TR::RealRegister::gr0);
      }
   }

bool TR::PPCMemInstruction::refsRegister(TR::Register *reg)
   {
   return getMemoryReference()->refsRegister(reg);
   }

bool TR::PPCMemInstruction::usesRegister(TR::Register *reg)
   {
   return getMemoryReference()->refsRegister(reg);
   }

void TR::PPCMemInstruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   getMemoryReference()->assignRegisters(this, cg());
   }

// TR::PPCMemSrc1Instruction:: member functions

TR::PPCMemSrc1Instruction::PPCMemSrc1Instruction(
      TR::InstOpCode::Mnemonic op,
      TR::Node *n,
      TR::MemoryReference *mf,
      TR::Register *sreg,
      TR::CodeGenerator *cg)
   : TR::PPCMemInstruction(op, n, mf, cg),
      _sourceRegister(sreg)
   {
   useRegister(sreg);
   if (mf->isUsingStaticTOC() && mf->getUnresolvedSnippet()==NULL)
      {
      cg->addRealRegisterInterference(sreg, TR::RealRegister::gr0);
      }
   }

TR::PPCMemSrc1Instruction::PPCMemSrc1Instruction(
      TR::InstOpCode::Mnemonic op,
      TR::Node *n,
      TR::MemoryReference *mf,
      TR::Register *sreg,
      TR::Instruction *precedingInstruction,
      TR::CodeGenerator *cg)
   : TR::PPCMemInstruction(op, n, mf, precedingInstruction, cg),
      _sourceRegister(sreg)
   {
   useRegister(sreg);
   if (mf->isUsingStaticTOC() && mf->getUnresolvedSnippet()==NULL)
      {
      cg->addRealRegisterInterference(sreg, TR::RealRegister::gr0);
      }
   }

TR::Register *TR::PPCMemSrc1Instruction::getMemoryDataRegister()
   {
   return getSourceRegister();
   }

bool TR::PPCMemSrc1Instruction::refsRegister(TR::Register *reg)
   {
   if (getMemoryReference()->refsRegister(reg) == true ||
       reg == getSourceRegister())
      {
      return true;
      }
   return false;
   }

bool TR::PPCMemSrc1Instruction::defsRegister(TR::Register *reg)
   {
   return false;
   }

bool TR::PPCMemSrc1Instruction::defsRealRegister(TR::Register *reg)
   {
   return false;
   }

bool TR::PPCMemSrc1Instruction::usesRegister(TR::Register *reg)
   {
   if (getMemoryReference()->refsRegister(reg) == true ||
       reg == getSourceRegister())
      {
      return true;
      }
   return false;
   }

void TR::PPCMemSrc1Instruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   TR::MemoryReference *mref = getMemoryReference();
   TR::Register           *sourceVirtual = getSourceRegister();
   TR::Register           *mBaseVirtual = mref->getModBase();
   TR::Machine *machine = cg()->machine();
   TR::RealRegister       *assignedRegister, *mBaseReal;
   bool                   excludeGPR0 = mref->isUsingStaticTOC() &&
                                        (mref->getUnresolvedSnippet() == NULL) &&
                                        (mref->getTOCOffset()>UPPER_IMMED || mref->getTOCOffset()<LOWER_IMMED);


   sourceVirtual->block();
   TR::PPCMemInstruction::assignRegisters(kindToBeAssigned);
   sourceVirtual->unblock();
   mBaseReal = (mBaseVirtual==NULL)?NULL:toRealRegister(mref->getModBase());

   mref->blockRegisters();
   assignedRegister = sourceVirtual->getAssignedRealRegister();
   if (excludeGPR0 && (assignedRegister != NULL) &&
       (toRealRegister(assignedRegister) == machine->getRealRegister(TR::RealRegister::gr0)))
      {
      TR::RealRegister    *alternativeRegister;

      if ((alternativeRegister = machine->findBestFreeRegister(this, sourceVirtual->getKind(), excludeGPR0, false, sourceVirtual)) == NULL)
         {
         cg()->setRegisterAssignmentFlag(TR_RegisterSpilled);
         alternativeRegister = machine->freeBestRegister(this, sourceVirtual, NULL, excludeGPR0);
         }
      machine->coerceRegisterAssignment(this, sourceVirtual, toRealRegister(alternativeRegister)->getRegisterNumber());
      assignedRegister = alternativeRegister;
      }
   else
      {
      if (assignedRegister == NULL)
         {
         assignedRegister = machine->assignOneRegister(this, sourceVirtual, excludeGPR0);
         }
      }
   mref->unblockRegisters();

   machine->decFutureUseCountAndUnlatch(sourceVirtual);

   setSourceRegister(assignedRegister);

   if (mBaseVirtual!=NULL)
      {
      machine->decFutureUseCountAndUnlatch(mBaseVirtual);
      }
   }

TR::Register *TR::PPCMemSrc1Instruction::getSourceRegisterForStmw(uint32_t i)
   {
   // Index 0:   maps to base register of stmw
   // Index 1-N: map to the N stored registers of stmw
   // Index >N:  NULL
   if (i==0) return getMemoryReference()->getBaseRegister();

   TR::RealRegister::RegNum rrFirstSaved, rrWant;

   rrFirstSaved = toRealRegister(getSourceRegister())->getRegisterNumber();
   rrWant = (TR::RealRegister::RegNum)(rrFirstSaved+(i-1));
   if (rrWant <= TR::RealRegister::LastGPR)
       {
      TR::Machine *machine = cg()->machine();
       return machine->getRealRegister(rrWant);
       }
   return NULL;
   }

TR::PPCTrg1MemInstruction::PPCTrg1MemInstruction(
      TR::InstOpCode::Mnemonic op,
      TR::Node *n,
      TR::Register *treg,
      TR::MemoryReference *mf,
      TR::CodeGenerator *cg,
      int32_t hint)
   : TR::PPCTrg1Instruction(op, n, treg, cg),
      _memoryReference(mf)
   {
   // If we set the hints, the instructions have to be lwarx or ldarx
   // Also control that the hints are set correctly for the type of instruction
   //
   if (encodeMutexHint())
      {
      _hint = hint;
      }
   else
      {
      _hint = PPCOpProp_NoHint;
      }

   TR_ASSERT(_hint == PPCOpProp_NoHint ||
          ( (op == TR::InstOpCode::lwarx || op == TR::InstOpCode::ldarx) &&
          (_hint == PPCOpProp_LoadReserveAtomicUpdate) || (_hint == PPCOpProp_LoadReserveExclusiveAccess)),"Hint set for the wrong instruction");

   if (getOpCode().offsetRequiresWordAlignment())
      {
      mf->setOffsetRequiresWordAlignment(n, cg, getPrev());
      }

   mf->bookKeepingRegisterUses(this, cg);
   TR::Register *baseReg = mf->getBaseRegister();
   if (baseReg != NULL)
      {
      cg->addRealRegisterInterference(baseReg, TR::RealRegister::gr0);
      }

   if (mf->isUsingStaticTOC() && mf->getUnresolvedSnippet()==NULL)
      {
      cg->addRealRegisterInterference(treg, TR::RealRegister::gr0);
      }
   }

TR::PPCTrg1MemInstruction::PPCTrg1MemInstruction(
      TR::InstOpCode::Mnemonic op,
      TR::Node *n,
      TR::Register *treg,
      TR::MemoryReference *mf,
      TR::Instruction *precedingInstruction,
      TR::CodeGenerator *cg,
      int32_t hint)
   : TR::PPCTrg1Instruction(op, n, treg, precedingInstruction, cg),
      _memoryReference(mf)
   {
   // If we set the hints, the instructions have to be lwarx or ldarx
   // Also control that the hints are set correctly for the type of instruction
   if (encodeMutexHint())
      {
      _hint = hint;
      }
   else
      {
      _hint = PPCOpProp_NoHint;
      }

   TR_ASSERT(_hint == PPCOpProp_NoHint ||
          ( (op == TR::InstOpCode::lwarx || op == TR::InstOpCode::ldarx) &&
          (_hint == PPCOpProp_LoadReserveAtomicUpdate) || (_hint == PPCOpProp_LoadReserveExclusiveAccess)),"Hint set for the wrong instruction");

   if (getOpCode().offsetRequiresWordAlignment())
      {
      mf->setOffsetRequiresWordAlignment(n, cg, getPrev());
      }
   mf->bookKeepingRegisterUses(this, cg);
   TR::Register *baseReg = mf->getBaseRegister();
   if (baseReg != NULL)
      {
      cg->addRealRegisterInterference(baseReg, TR::RealRegister::gr0);
      }

   if (mf->isUsingStaticTOC() && mf->getUnresolvedSnippet()==NULL)
      {
      cg->addRealRegisterInterference(treg, TR::RealRegister::gr0);
      }
   }


bool TR::PPCTrg1MemInstruction::encodeMutexHint()
   {
   return cg()->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P6) && (getOpCodeValue() == TR::InstOpCode::lwarx || getOpCodeValue() == TR::InstOpCode::ldarx);
   }


TR::Register *TR::PPCTrg1MemInstruction::getTargetRegisterForLmw(uint32_t i)
   {
   // Index 0:   maps to base register of stmw
   // Index 1-N: map to the N stored registers of stmw
   // Index >N:  NULL
   if (i==0) return getMemoryReference()->getBaseRegister();

   TR::RealRegister::RegNum rrFirstSaved, rrWant;

   rrFirstSaved = toRealRegister(getTargetRegister())->getRegisterNumber();
   rrWant = (TR::RealRegister::RegNum)(rrFirstSaved+(i-1));
   if (rrWant <= TR::RealRegister::LastGPR)
       {
      TR::Machine *machine = cg()->machine();
       return machine->getRealRegister(rrWant);
       }
   return NULL;
   }


// TR::PPCTrg1MemInstruction:: member functions

TR::Register *TR::PPCTrg1MemInstruction::getMemoryDataRegister()
   {
   return getTargetRegister();
   }

bool TR::PPCTrg1MemInstruction::refsRegister(TR::Register *reg)
   {
   if (reg == getTargetRegister() ||
       getMemoryReference()->refsRegister(reg) == true)
      {
      return true;
      }
   return false;
   }

bool TR::PPCTrg1MemInstruction::usesRegister(TR::Register *reg)
   {
   if (getMemoryReference()->refsRegister(reg) == true)
      {
      return true;
      }
   return false;
   }

void TR::PPCTrg1MemInstruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   TR::MemoryReference *mref = getMemoryReference();
   TR::Register           *targetVirtual = getTargetRegister();
   TR::Register           *mBaseVirtual = mref->getModBase();
   TR::RealRegister       *mBaseReal;
   bool                   excludeGPR0 = mref->isUsingStaticTOC() &&
                                        (mref->getUnresolvedSnippet() == NULL) &&
                                        (mref->getTOCOffset()>UPPER_IMMED || mref->getTOCOffset()<LOWER_IMMED);

   if (targetVirtual == mref->getBaseRegister())
      excludeGPR0 = true;

   mref->blockRegisters();
   TR::PPCTrg1Instruction::assignRegisters(kindToBeAssigned, excludeGPR0);
   mref->unblockRegisters();

   targetVirtual->block();
   mref->assignRegisters(this, cg());
   targetVirtual->unblock();

   mBaseReal = (mBaseVirtual==NULL)?NULL:toRealRegister(mref->getModBase());

   if (mBaseVirtual!=NULL)
      {
      cg()->machine()->decFutureUseCountAndUnlatch(mBaseVirtual);
      }
   }

// TR::PPCControlFlowInstruction:: member functions

bool TR::PPCControlFlowInstruction::refsRegister(TR::Register *reg)
   {
   int numTargets;
   int numSources;
   int i;
   numTargets = getNumTargets();
   numSources = getNumSources();
   for (i=0; i<numTargets; i++)
      {
      if (reg == getTargetRegister(i))
         {
         return true;
         }
      }
   for (i=0; i<numSources; i++)
      {
      if (!isSourceImmediate(i) && reg == getSourceRegister(i))
         {
         return true;
         }
      }
   return false;
   }

bool TR::PPCControlFlowInstruction::defsRegister(TR::Register *reg)
   {
   int numTargets;
   int i;
   numTargets = getNumTargets();
   for (i=0; i<numTargets; i++)
      {
      if (reg == getTargetRegister(i))
         {
         return true;
         }
      }
   return false;
   }

bool TR::PPCControlFlowInstruction::defsRealRegister(TR::Register *reg)
   {
   int numTargets;
   int i;
   numTargets = getNumTargets();
   for (i=0; i<numTargets; i++)
      {
      if (reg == getTargetRegister(i)->getAssignedRegister())
         {
         return true;
         }
      }
   return false;
   }

bool TR::PPCControlFlowInstruction::usesRegister(TR::Register *reg)
   {
   int numSources;
   int i;
   numSources = getNumSources();
   for (i=0; i<numSources; i++)
      {
      if (!isSourceImmediate(i) && reg == getSourceRegister(i))
         {
         return true;
         }
      }
   return false;
   }

void TR::PPCControlFlowInstruction::assignRegisters(TR_RegisterKinds kindToBeAssigned)
   {
   TR::Machine *machine = cg()->machine();
   TR::Node          *currentNode = getNode();
   TR::RealRegister  *realSources[8], *realTargets[5];
   int numSources;
   int numTargets;
   int i;
   numSources = getNumSources();
   numTargets = getNumTargets();
   if (_conditions != NULL)
      _conditions->assignPostConditionRegisters(this, kindToBeAssigned, cg());
   for (i=0; i<numSources; i++)
      {
      if (!isSourceImmediate(i))
         getSourceRegister(i)->block();
      }
   for (i=0; i<numTargets; i++)
      {
      getTargetRegister(i)->block();
      }
   for (i=0; i<numTargets; i++)
      {
      TR::Register         *targetVirtual = getTargetRegister(i);
      TR::RealRegister  *assignedRegister = targetVirtual->getAssignedRealRegister();
      if (assignedRegister == NULL)
         {
         assignedRegister = machine->assignOneRegister(this, targetVirtual, false);
         }
      realTargets[i] = assignedRegister;
      targetVirtual->block();
      }
   for (i=0; i<numSources; i++)
      {
      if (!isSourceImmediate(i))
         {
         TR::Register      *sourceVirtual = getSourceRegister(i);
         TR::RealRegister  *assignedRegister = sourceVirtual->getAssignedRealRegister();
         if (assignedRegister == NULL)
            {
            assignedRegister = machine->assignOneRegister(this, sourceVirtual, false);
            }
         realSources[i] = assignedRegister;
         sourceVirtual->block();
         }
      }
   for (i=0; i<numTargets; i++)
      {
      TR::Register *targetVirtual = getTargetRegister(i);

      targetVirtual->unblock();
      machine->decFutureUseCountAndUnlatch(targetVirtual);
      setTargetRegister(i, realTargets[i]);
      }
   for (i=0; i<numSources; i++)
      {
      if (!isSourceImmediate(i))
         {
         TR::Register *sourceVirtual = getSourceRegister(i);

         sourceVirtual->unblock();
         machine->decFutureUseCountAndUnlatch(sourceVirtual);
         setSourceRegister(i, realSources[i]);
         }
      }
   // Now that registers have been allocated, expand the code
   TR::Instruction *cursor = this;
   TR::LabelSymbol *label2   = TR::LabelSymbol::create(cg()->trHeapMemory(),cg());
   TR::LabelSymbol *label1;
   TR::MemoryReference *tempMR = NULL;
   TR::SymbolReference    *temp;

   switch(getOpCode().getOpCodeValue())
      {
      case TR::InstOpCode::iflong:
         if (isSourceImmediate(2))
            {
            if (currentNode->getOpCode().isUnsigned())
               cg()->traceRAInstruction(cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::cmpli4, currentNode, getTargetRegister(0), getSourceRegister(0), getSourceImmediate(2), cursor));
            else
               cg()->traceRAInstruction(cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::cmpi4, currentNode, getTargetRegister(0), getSourceRegister(0), getSourceImmediate(2), cursor));
            }
         else
            {
            if (currentNode->getOpCode().isUnsigned())
               cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::cmpl4, currentNode, getTargetRegister(0), getSourceRegister(0), getSourceRegister(2), cursor));
            else
               cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::cmp4, currentNode, getTargetRegister(0), getSourceRegister(0), getSourceRegister(2), cursor));
            }
         if (getOpCode2Value() == TR::InstOpCode::bne)
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, currentNode, getLabelSymbol(), getTargetRegister(0), cursor));
         else
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, currentNode, label2, getTargetRegister(0), cursor));
         if (isSourceImmediate(3))
            cg()->traceRAInstruction(cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::cmpli4, currentNode, getTargetRegister(0), getSourceRegister(1), getSourceImmediate(3), cursor));
         else
            cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::cmpl4, currentNode, getTargetRegister(0), getSourceRegister(1), getSourceRegister(3), cursor));
         if (getOpCode2Value() == TR::InstOpCode::beq)
            {
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), getOpCode2Value(), currentNode, getLabelSymbol(), getTargetRegister(0), cursor));
            cg()->traceRAInstruction(cursor = generateLabelInstruction(cg(), TR::InstOpCode::label, currentNode, label2, cursor));
            }
         else
            {
            cg()->traceRAInstruction(cursor = generateLabelInstruction(cg(), TR::InstOpCode::label, currentNode, label2, cursor));
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), getOpCode2Value(), currentNode, getLabelSymbol(), getTargetRegister(0), cursor));
            }
         break;
      case TR::InstOpCode::idiv:
         cg()->traceRAInstruction(cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::cmpi4, currentNode, getTargetRegister(0), getSourceRegister(1), -1, cursor));
         cg()->traceRAInstruction(cursor = generateTrg1Src1Instruction(cg(), TR::InstOpCode::neg, currentNode, getTargetRegister(1), getSourceRegister(0), cursor));
         if (cg()->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_GP))
            // use PPC AS branch hint
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::beq, PPCOpProp_BranchUnlikely, currentNode, label2, getTargetRegister(0), cursor));
         else
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::beq, currentNode, label2, getTargetRegister(0), cursor));
         cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::divw, currentNode, getTargetRegister(1), getSourceRegister(0), getSourceRegister(1), cursor));
         cg()->traceRAInstruction(cursor = generateLabelInstruction(cg(), TR::InstOpCode::label, currentNode, label2, cursor));
         break;
      case TR::InstOpCode::irem:
         cg()->traceRAInstruction(cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::cmpi4, currentNode, getTargetRegister(0), getSourceRegister(1), -1, cursor));
         cg()->traceRAInstruction(cursor = generateTrg1ImmInstruction(cg(), TR::InstOpCode::li, currentNode, getTargetRegister(1), 0, cursor));
         if (cg()->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_GP))
            // use PPC AS branch hint
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::beq, PPCOpProp_BranchUnlikely, currentNode, label2, getTargetRegister(0), cursor));
         else
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::beq, currentNode, label2, getTargetRegister(0), cursor));
#ifdef OMR_ENABLE_POWER_INTMODULO // Re-enable this code with new hardware update
         if (cg()->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P9))
            {
            cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::modsw, currentNode, getTargetRegister(1), getSourceRegister(0), getSourceRegister(1), cursor));
            }
         else
#endif
            {
            cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::divw, currentNode, getTargetRegister(1), getSourceRegister(0), getSourceRegister(1), cursor));
            cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::mullw, currentNode, getTargetRegister(1), getSourceRegister(1), getTargetRegister(1), cursor));
            cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::subf, currentNode, getTargetRegister(1), getTargetRegister(1), getSourceRegister(0), cursor));
            }
         cg()->traceRAInstruction(cursor = generateLabelInstruction(cg(), TR::InstOpCode::label, currentNode, label2, cursor));
         break;
      case TR::InstOpCode::ldiv:
         cg()->traceRAInstruction(cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::cmpi8, currentNode, getTargetRegister(0), getSourceRegister(1), -1, cursor));
         cg()->traceRAInstruction(cursor = generateTrg1Src1Instruction(cg(), TR::InstOpCode::neg, currentNode, getTargetRegister(1), getSourceRegister(0), cursor));
         if (cg()->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_GP))
            // use PPC AS branch hint
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::beq, PPCOpProp_BranchUnlikely, currentNode, label2, getTargetRegister(0), cursor));
         else
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::beq, currentNode, label2, getTargetRegister(0), cursor));
         cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::divd, currentNode, getTargetRegister(1), getSourceRegister(0), getSourceRegister(1), cursor));
         cg()->traceRAInstruction(cursor = generateLabelInstruction(cg(), TR::InstOpCode::label, currentNode, label2, cursor));
         break;
      case TR::InstOpCode::lrem:
         cg()->traceRAInstruction(cursor = generateTrg1Src1ImmInstruction(cg(), TR::InstOpCode::cmpi8, currentNode, getTargetRegister(0), getSourceRegister(1), -1, cursor));
         cg()->traceRAInstruction(cursor = generateTrg1ImmInstruction(cg(), TR::InstOpCode::li, currentNode, getTargetRegister(1), 0, cursor));
         if (cg()->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_GP))
            // use PPC AS branch hint
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::beq, PPCOpProp_BranchUnlikely, currentNode, label2, getTargetRegister(0), cursor));
         else
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::beq, currentNode, label2, getTargetRegister(0), cursor));
#ifdef OMR_ENABLE_POWER_INTMODULO // Re-enable this code with new hardware update
         if (cg()->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P9))
            {
            cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::modsd, currentNode, getTargetRegister(1), getSourceRegister(0), getSourceRegister(1), cursor));
            }
         else
#endif
            {
            cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::divd, currentNode, getTargetRegister(1), getSourceRegister(0), getSourceRegister(1), cursor));
            cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::mulld, currentNode, getTargetRegister(1), getSourceRegister(1), getTargetRegister(1), cursor));
            cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::subf, currentNode, getTargetRegister(1), getTargetRegister(1), getSourceRegister(0), cursor));
            }
         cg()->traceRAInstruction(cursor = generateLabelInstruction(cg(), TR::InstOpCode::label, currentNode, label2, cursor));
         break;
      case TR::InstOpCode::d2i:
         cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::fcmpu, currentNode, getTargetRegister(0), getSourceRegister(0), getSourceRegister(0), cursor));
         cg()->traceRAInstruction(cursor = generateTrg1Src1Instruction(cg(), TR::InstOpCode::fctiwz, currentNode, getTargetRegister(1), getSourceRegister(0), cursor));
         cg()->traceRAInstruction(cursor = generateTrg1ImmInstruction(cg(), TR::InstOpCode::li, currentNode, getTargetRegister(2), 0, cursor));

         if (!cg()->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8))
            {
            tempMR = TR::MemoryReference::createWithDisplacement(cg(), cg()->getStackPointerRegister(), -8, 8);
            cg()->traceRAInstruction(cursor = generateMemSrc1Instruction(cg(), TR::InstOpCode::stfd, currentNode, tempMR, getTargetRegister(1), cursor));
            }

         if (cg()->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_GP))
            // use PPC AS branch hint
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, currentNode, label2, getTargetRegister(0), cursor));
         else
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, currentNode, label2, getTargetRegister(0), cursor));

         if (cg()->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8))
            cg()->traceRAInstruction(cursor = generateTrg1Src1Instruction(cg(), TR::InstOpCode::mfvsrwz, currentNode, getTargetRegister(2), getTargetRegister(1), cursor));
         else
            cg()->traceRAInstruction(cursor = generateTrg1MemInstruction(cg(), TR::InstOpCode::lwz, currentNode, getTargetRegister(2), TR::MemoryReference::createWithMemRef(cg(), currentNode, *tempMR, 4, 4), cursor));
         cg()->traceRAInstruction(cursor = generateLabelInstruction(cg(), TR::InstOpCode::label, currentNode, label2, cursor));

         break;
      case TR::InstOpCode::d2l:
         cg()->traceRAInstruction(cursor = generateTrg1Src2Instruction(cg(), TR::InstOpCode::fcmpu, currentNode, getTargetRegister(0), getSourceRegister(0), getSourceRegister(0), cursor));
         cg()->traceRAInstruction(cursor = generateTrg1Src1Instruction(cg(), TR::InstOpCode::fctidz, currentNode, getTargetRegister(1), getSourceRegister(0), cursor));

         if (cg()->comp()->target().is64Bit())
            cg()->traceRAInstruction(cursor = generateTrg1ImmInstruction(cg(), TR::InstOpCode::li, currentNode, getTargetRegister(2), 0, cursor));
         else
            {
            cg()->traceRAInstruction(cursor = generateTrg1ImmInstruction(cg(), TR::InstOpCode::li, currentNode, getTargetRegister(2), 0, cursor));
            cg()->traceRAInstruction(cursor = generateTrg1ImmInstruction(cg(), TR::InstOpCode::li, currentNode, getTargetRegister(3), 0, cursor));
            }
         if (!cg()->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8)|| cg()->comp()->target().is32Bit())
            {
            tempMR = TR::MemoryReference::createWithDisplacement(cg(), cg()->getStackPointerRegister(), -8, 8);
            cg()->traceRAInstruction(cursor = generateMemSrc1Instruction(cg(), TR::InstOpCode::stfd, currentNode, tempMR, getTargetRegister(1), cursor));
            }

         if (cg()->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_GP))
            // use PPC AS branch hint
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, PPCOpProp_BranchUnlikely, currentNode, label2, getTargetRegister(0), cursor));
         else
            cg()->traceRAInstruction(cursor = generateConditionalBranchInstruction(cg(), TR::InstOpCode::bne, currentNode, label2, getTargetRegister(0), cursor));

         if (cg()->comp()->target().is64Bit())
            {
            if (cg()->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_PPC_P8) && cg()->comp()->target().is64Bit())
               cg()->traceRAInstruction(cursor = generateTrg1Src1Instruction(cg(), TR::InstOpCode::mfvsrd, currentNode, getTargetRegister(2), getTargetRegister(1), cursor));
            else
               cg()->traceRAInstruction(cursor = generateTrg1MemInstruction(cg(), TR::InstOpCode::ld, currentNode, getTargetRegister(2), tempMR, cursor));
            }
         else
            {
            cg()->traceRAInstruction(cursor = generateTrg1MemInstruction(cg(), TR::InstOpCode::lwz, currentNode, getTargetRegister(2), TR::MemoryReference::createWithMemRef(cg(), currentNode, *tempMR, 0, 4), cursor));
            cg()->traceRAInstruction(cursor = generateTrg1MemInstruction(cg(), TR::InstOpCode::lwz, currentNode, getTargetRegister(3), TR::MemoryReference::createWithMemRef(cg(), currentNode, *tempMR, 4, 4), cursor));
            }
         cg()->traceRAInstruction(cursor = generateLabelInstruction(cg(), TR::InstOpCode::label, currentNode, label2, cursor));

         break;
      default:
         TR_ASSERT(false,"unknown control flow instruction ");
      }

   if (_conditions != NULL)
      _conditions->assignPreConditionRegisters(this->getPrev(), kindToBeAssigned, cg());
   }
